package protocol.common.httpclient;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

import protocol.common.httpclient.response.HttpResponseDefaultHandler;

/**
 * HttpClient 工具类，提供有连接池方式的搞笑http访问接口
 *
 * @author 陈杰
 * @version 1.0
 * @since 2016年3月3日 00:18:48
 *
 * Copyright (c) 2016 陈杰(chenjie_java@aliyun.com)
 */
public class HttpRequestManager {
	
	private static Map<String,HttpRequestManager> managerPool = new HashMap<String,HttpRequestManager>();
	
	/**
	 * HttpClient 连接池
	 * */
	private PoolingHttpClientConnectionManager connectionManager;
	
	private CloseableHttpClient httpClient;

	/**
	 * Header 参数
	 * */
	private Map<String,String> headParametersMap;
	
	/**
	 * 请求配置
	 * */
	private RequestConfig requestConfig;

	/**
	 * 使用默认参数初始化，初始化之后可以根据需要设置Header
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)</p>
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)
	 *                             .initHeadParameterMap(key,value)</p>
	 * 
	 * @return HttpRequestManager
	 * */
	public static HttpRequestManager init() {
		HttpRequestManager httpManager = new HttpRequestManager();
		httpManager.initConnectionManager(200, 100);
		httpManager.initRequestConfig(60000, 60000, 60000);
		httpManager.headParametersMap = new HashMap<String,String>();
		httpManager.httpClient = httpManager.getHttpClient();
		return httpManager;
	}
	
	/**
	 * HttpClient初始化，初始化之后可以根据需要设置Header
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)</p>
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)
	 *                             .initHeadParameterMap(key,value)</p>
	 *                             
	 * @param maxTotalConnection <p>最大连接数</p>
	 * @param maxRouteConnection <p>最大路由基础连接数</p>
	 * @param connRequestTimeout <p>连接请求超时时间</p>
	 * @param connTimeout        <p>连接超时时间</p>
	 * @param socketTimeout      <p>socket连接超时时间</p>
	 * 
	 * @return HttpRequestManager
	 * */
	public static HttpRequestManager init(int maxTotalConnection,int maxRouteConnection,int connRequestTimeout,int connTimeout,int socketTimeout) {
		HttpRequestManager httpManager = new HttpRequestManager();
		httpManager.initConnectionManager(200, 100);
		httpManager.initRequestConfig(60000, 60000, 60000);
		httpManager.headParametersMap = new HashMap<String,String>();
		httpManager.httpClient = httpManager.getHttpClient();
		return httpManager;
	}
	
	/**
	 * 添加默认Header设置
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)</p>
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)
	 *                             .initHeadParameterMap(key,value)</p>
	 *                             
	 * @param key   <p>header key</p>
	 * @param value <p>header value</p>
	 * 
	 * @return HttpRequestManager
	 * */
	public HttpRequestManager initHeadParameterMap(String key,String value){
		this.headParametersMap.put(key, value);
		return this;
	}
	
	/**
	 * 批量添加默认Header设置,
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)</p>
	 * <p>HttpRequestManager.init().initHeadParameterMap(key,value)
	 *                             .initHeadParameterMap(key,value)</p>
	 *                             
	 * @param parametersMap   <p>header key</p>
	 * 
	 * @return HttpRequestManager
	 * */
	public HttpRequestManager initHeadParameterMap(Map<String,String> parametersMap){
		for(String key : parametersMap.keySet()){
			this.headParametersMap.put(key,parametersMap.get(key));
		}
		return this;
	}
	
	public HttpRequestManager cacheInMap(String mapKey){
		return HttpRequestManager.managerPool.put(mapKey, this);
	}
	
	public static HttpRequestManager pullManagerFromMap(String mapKey){
		HttpRequestManager httpRequestManager = HttpRequestManager.managerPool.get(mapKey);
		httpRequestManager = HttpRequestManager.init().cacheInMap(mapKey);
		return httpRequestManager;
	}
	
	private void initConnectionManager(int maxTotalConnection,int maxRouteConnection){
		// 需要通过以下代码声明对https连接支持
		ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
		LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				        .register("http", plainsf)
				        .register("https", sslsf)
				        .build();
		// 初始化连接管理器
		connectionManager = new PoolingHttpClientConnectionManager(registry);
		// Increase max total connection to 200
		connectionManager.setMaxTotal(maxTotalConnection);
		// Increase default max connection per route to 20
		connectionManager.setDefaultMaxPerRoute(maxRouteConnection);
	}
	
	private void initRequestConfig(int connRequestTimeout,int connTimeout,int socketTimeout){
		requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(connRequestTimeout)
				.setConnectTimeout(connTimeout)
				.setSocketTimeout(socketTimeout)
				.build();
	}
	
	private HttpPost createHttpPost(String url){
		HttpPost httpPost = new HttpPost(url);
		for(String key : headParametersMap.keySet()){
			httpPost.addHeader(key, headParametersMap.get(key));
		}
		httpPost.setConfig(requestConfig);
		return httpPost;
	}

	private HttpGet createHttpGet(String url){
		HttpGet httpGet = new HttpGet(url);
		for(String key : headParametersMap.keySet()){
			httpGet.addHeader(key, headParametersMap.get(key));
		}
		httpGet.setConfig(requestConfig);
		return httpGet;
	}
	
	/**
	 * 获取HttpClient对象
	 * 
	 * @param httpRequestRetryHandler 请求处理类
	 * @return CloseableHttpClient 
	 * */
	public CloseableHttpClient getHttpClient(HttpRequestRetryHandler httpRequestRetryHandler) {
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager)
				.setRetryHandler(httpRequestRetryHandler).build();
		return httpClient;
	}
	
	/**
	 * 获取HttpClient对象
	 * 
	 * @return CloseableHttpClient 
	 * */
	public CloseableHttpClient getHttpClient() {
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
		return httpClient;
	}
	
	public void closeHttpClient(){
		if(httpClient != null){
			try {
				
				httpClient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * 发送post请求，默认启动失败重发机制
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler postByHandler(String url){
		HttpResponseDefaultHandler responseHandler = this.post(url,httpClient,null);
		return responseHandler;
	}
	
	/**
	 * 发送post请求，默认启动失败重发机制
	 * 
	 * @param actionCount <p>失败重发次数</p>
	 * @param sleepTime <p>每次失败休眠时间</p>
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler postByHandler(int actionCount,int sleepTime,String url){
		HttpResponseDefaultHandler responseHandler = this.post(url,httpClient, null);
		return responseHandler;
	}
	
	/**
	 * 发送post请求，默认启动失败重发机制
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler postByHandler(String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.post(url,httpClient,parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送post请求，可以设置失败重发
	 * 
	 * @param actionCount <p>失败重发次数</p>
	 * @param sleepTime <p>每次失败休眠时间</p>
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler postByHandler(int actionCount,int sleepTime,String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.post(url,httpClient,parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送post请求
	 * 
	 * @param url  <p>请求地址</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler post(String url){
		HttpResponseDefaultHandler responseHandler =  this.post(url, httpClient, null);
		return responseHandler;
	}
	
	/**
	 * 发送post请求
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler post(String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.post(url, httpClient, parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送post请求
	 * 
	 * @param url  <p>请求地址</p>
	 * @param httpClient  <p>httpClient</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler post(String url,CloseableHttpClient httpClient,Map<String,String> parametersObject){
		HttpPost httpPost = this.createHttpPost(url);
		CloseableHttpResponse response = null;
		try {
			if(parametersObject!=null && parametersObject.size()>0){
				List<NameValuePair> nvps = new ArrayList<NameValuePair>();
				for(String key : parametersObject.keySet()){
					nvps.add(new BasicNameValuePair(key,parametersObject.get(key)));  
				}
		        httpPost.setEntity( new UrlEncodedFormEntity(nvps,"utf-8"));  
			}
			response = httpClient.execute(httpPost,HttpClientContext.create());
		} catch (Exception e) {
			e.printStackTrace();
			httpPost.abort();
		}
		return HttpResponseDefaultHandler.createResponseHandler(response);
	}

	/**
	 * 发送get请求,所有参数都有进行URLEncoder，默认启动失败重发机制
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler getByHandler(String url){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient,null);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder，可以设置失败重发
	 * 
	 * @param actionCount <p>失败重发次数</p>
	 * @param sleepTime <p>每次失败休眠时间</p>
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler getByHandler(int actionCount,int sleepTime,String url){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient,null);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder，默认启动失败重发机制
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler getByHandler(String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient, parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder，可以设置失败重发
	 * 
	 * @param actionCount <p>失败重发次数</p>
	 * @param sleepTime <p>每次失败休眠时间</p>
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler getByHandler(int actionCount,int sleepTime,String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient,parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder
	 * 
	 * @param url  <p>请求地址</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler get(String url){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient,null);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder
	 * 
	 * @param url  <p>请求地址</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler get(String url,Map<String,String> parametersObject){
		HttpResponseDefaultHandler responseHandler = this.get(url,httpClient, parametersObject);
		return responseHandler;
	}
	
	/**
	 * 发送get请求,所有参数都有进行URLEncoder
	 * 
	 * @param url  <p>请求地址</p>
	 * @param httpClient  <p>httpClient</p>
	 * @param parametersObject  <p>请求参数集合</p>
	 * 
	 * @return HttpResponseDefaultHandler 默认的响应处理类
	 * */
	public HttpResponseDefaultHandler get(String url,CloseableHttpClient httpClient,Map<String,String> parametersObject){
		CloseableHttpResponse response = null;
		HttpGet httpGet = null;
		try {
			if(parametersObject!=null && parametersObject.size()>0){
				StringBuilder parametersBuilder = new StringBuilder(url);
				parametersBuilder.append("?");
				for(String key : parametersObject.keySet()){
					String value = URLEncoder.encode(parametersObject.get(key),"utf-8");
					parametersBuilder.append(key).append("=").append(value).append("&");
				}
				parametersBuilder.deleteCharAt(parametersBuilder.length()-1);
				httpGet = this.createHttpGet(parametersBuilder.toString());
			}
			response = httpClient.execute(httpGet,HttpClientContext.create());
		} catch (Exception e) {
			e.printStackTrace();
			if(httpGet!=null)httpGet.abort();
		}
		return HttpResponseDefaultHandler.createResponseHandler(response);
	}
	
	
	public static void main(String[] args) {
		
		HttpRequestManager.init().initHeadParameterMap("User-Agent", "Mozilla/5.0")
							     .initHeadParameterMap("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
							     .initHeadParameterMap("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")//"en-US,en;q=0.5")
							     .initHeadParameterMap("Accept-Charset", "ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7")
							     .cacheInMap("CacheKey");
		
		BlockingQueue<Map<String,String>> paramtersObjectList = new ArrayBlockingQueue<Map<String,String>>(20000);
		
		
		for(int i = 0;i<10;i++){
			Map<String,String> paramtersMap = new HashMap<String,String>();
			paramtersMap.put("username","ChenJie");
			paramtersMap.put("password","86c09978e5d437ea471363219a52cfde");
			paramtersMap.put("sqnumber","123");
			paramtersMap.put("mobile","13951678171");
			paramtersMap.put("content","【全民星彩】短信内容,长长长长长长长长"+i);
			paramtersObjectList.add(paramtersMap);
		}
		
		class GetRunnable implements Runnable {
			private HttpRequestManager httpRequestManager;
			private BlockingQueue<Map<String,String>> paramtersObjectList;
			private CloseableHttpClient httpClient;
			private int index;
	        public GetRunnable(int index,BlockingQueue<Map<String,String>> paramtersObjectList){
	        	this.index = index;
	        	this.paramtersObjectList = paramtersObjectList;
	        	this.httpRequestManager = HttpRequestManager.pullManagerFromMap("CacheKey");
	        	
	        }
	        @Override
	        public void run() {
	        	try {
	        		while(paramtersObjectList.size()>0){
	        			CloseableHttpClient httpClient = this.httpRequestManager.getHttpClient();
		            	Map<String,String> parametersObject = paramtersObjectList.poll();
		            	if(parametersObject==null){continue;}
		            	Long timeMark = System.currentTimeMillis();
		            	HttpResponseDefaultHandler handler = httpRequestManager.post("http://139.196.198.174/bxsms-web-interface/SendMsg",httpClient,parametersObject);
		                System.out.println("<系统信息> HttpClient:"+httpClient.hashCode()+" Time:"+(System.currentTimeMillis()-timeMark)+" Index:"+index+" "+handler.getResponseString());
	        		}
	        		System.out.println("<系统信息> Index:"+index+" 队列数据发送完毕关闭连接");
	        	} catch (IOException e) {
	        		System.out.println("<系统信息> Index:"+index+" "+e.getMessage());
	            } finally {
	            	try {
						httpClient.close();
					} catch (IOException e) {
					}
	            }
	        }
	    } 
		
		
        ExecutorService executors = Executors.newFixedThreadPool(10);
	      for(int i = 0; i< 2;i++){
	          executors.execute(new GetRunnable(i,paramtersObjectList));
	      }
//      executors.execute(new GetRunnable(0,paramtersObjectList));
		
	}
}